#include "string_util.hh"

namespace kratos { namespace corelib {

void StringUtil::splitOf(const std::string & src, const std::string & delim, std::vector<std::string>& result) {
    if (delim.size() >= src.size()) {
        return;
    }
    if (src.empty() || delim.empty()) {
        return;
    }
    result.clear();
    size_t end = 0;
    size_t begin = 0;
    while (end != std::string::npos) {
        end = src.find_first_of(delim, begin);
        if (end != std::string::npos) {
            result.push_back(src.substr(begin, end - begin));
        } else {
            result.push_back(src.substr(begin, std::string::npos));
        }
        begin = end + delim.size();
    }
}

void StringUtil::split(const std::string & src, const std::string & delim, std::vector<std::string>& result) {
    size_t end = 0;
    size_t begin = 0;
    std::string substr;
    result.clear();
    while (end != std::string::npos) {
        end = src.find(delim, begin);
        if (end != std::string::npos) {
            substr = src.substr(begin, end - begin);
        } else {
            substr = src.substr(begin, std::string::npos);
        }
        if (!substr.empty() && (substr != delim)) {
            result.push_back(substr);
        }
        begin = end + delim.size();
    }
}

void StringUtil::splitBy(const std::string & src, char delim, std::vector<std::string>& result) {
    result.clear();
    std::string item;
    for (auto& c : src) {
        if (c != delim) {
            item.push_back(c);
        } else {
            if (!item.empty()) {
                result.push_back(std::move(item));
            }
            item.push_back(delim);
        }
    }
    if (!item.empty()) {
        result.push_back(std::move(item));
    }
}

bool StringUtil::endWith(const std::string& src, const std::string& s) {
    if (s.size() >= src.size()) {
        return false;
    }
    if (src.empty() || s.empty()) {
        return false;
    }
    return src.compare(src.size() - s.size(), s.size(), s) == 0;
}

bool StringUtil::startWith(const std::string & src, const std::string & s) {
    if (s.size() >= src.size()) {
        return false;
    }
    if (src.empty() || s.empty()) {
        return false;
    }
    return src.compare(0, s.size(), s) == 0;
}

std::string StringUtil::remove(const std::string & src, const std::string & s) {
    if (s.size() >= src.size()) {
        return src;
    }
    if (s.empty() || src.empty()) {
        return src;
    }
    auto target = src;
    std::size_t pos = 0;
    while (pos != std::string::npos) {
        pos = target.find(s, pos);
        if (std::string::npos != pos) {
            target.erase(pos, s.size());
        } else {
            break;
        }
    }
    return target;
}

std::string StringUtil::trim(const std::string& src, const std::string & delim) {
    if (src.empty()) {
        return src;
    }
    std::string s(src);
    s.erase(0, s.find_first_not_of(delim));
    s.erase(s.find_last_not_of(delim) + 1);
    return s;
}

std::string StringUtil::ltrim(const std::string & src, const std::string & delim) {
    if (src.empty()) {
        return src;
    }
    std::string s(src);
    s.erase(0, s.find_first_not_of(delim));
    return s;
}

std::string StringUtil::rtrim(const std::string & src, const std::string & delim) {
    if (src.empty()) {
        return src;
    }
    std::string s(src);
    s.erase(s.find_last_not_of(delim) + 1);
    return s;
}

std::string StringUtil::replace(const std::string & src, const std::string & pattern, const std::string & dest) {
    if (pattern.size() > src.size()) {
        return src;
    }
    std::string::size_type pos = 0;
    auto srclen = pattern.size();
    auto dstlen = dest.size();
    std::string s(src);
    pos = s.find(pattern, pos);
    while (std::string::npos != pos) {
        s.replace(pos, srclen, dest);
        pos += dstlen;
        pos = s.find(pattern, pos);
    }
    return s;
}

std::string StringUtil::getFileName(const std::string & src) {
    if (src.empty()) {
        return src;
    }
    std::vector<std::string> result;
    std::string last;
    split(src, "/", result);
    if (result.size() == 1) {
        split(src, "\\", result);
        if (result.size() == 1) {
            last = src;
        } else {
            last = result.back();
        }
    } else {
        last = result.back();
    }
    result.clear();
    split(last, ".", result);
    if (result.size() == 1) {
        return last;
    }
    return result.front();
}

bool StringUtil::hasSubstring(const std::string& src, const std::string & sub) {
    return (src.find(sub) != std::string::npos);
}

}}
